/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var constants = {
    // Alphabet chars.
    CHAR_UPPERCASE_A: 65 /* A */
,
    CHAR_LOWERCASE_A: 97 /* a */
,
    CHAR_UPPERCASE_Z: 90 /* Z */
,
    CHAR_LOWERCASE_Z: 122 /* z */
,
    CHAR_UPPERCASE_C: 67 /* C */
,
    CHAR_LOWERCASE_B: 98 /* b */
,
    CHAR_LOWERCASE_E: 101 /* e */
,
    CHAR_LOWERCASE_N: 110 /* n */
,

    // Non-alphabetic chars.
    CHAR_DOT: 46 /* . */
,
    CHAR_FORWARD_SLASH: 47 /* / */
,
    CHAR_BACKWARD_SLASH: 92 /* \ */
,
    CHAR_VERTICAL_LINE: 124 /* | */
,
    CHAR_COLON: 58 /* : */
,
    CHAR_QUESTION_MARK: 63 /* ? */
,
    CHAR_UNDERSCORE: 95 /* _ */
,
    CHAR_LINE_FEED: 10 /* \n */
,
    CHAR_CARRIAGE_RETURN: 13 /* \r */
,
    CHAR_TAB: 9 /* \t */
,
    CHAR_FORM_FEED: 12 /* \f */
,
    CHAR_EXCLAMATION_MARK: 33 /* ! */
,
    CHAR_HASH: 35 /* # */
,
    CHAR_SPACE: 32 /*   */
,
    CHAR_NO_BREAK_SPACE: 160 /* \u00A0 */
,
    CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279 /* \uFEFF */
,
    CHAR_LEFT_SQUARE_BRACKET: 91, //* [ */
    CHAR_RIGHT_SQUARE_BRACKET: 93 /* ] */
,
    CHAR_LEFT_ANGLE_BRACKET: 60 /* < */
,
    CHAR_RIGHT_ANGLE_BRACKET: 62 /* > */
,
    CHAR_LEFT_CURLY_BRACKET: 123 /* { */
,
    CHAR_RIGHT_CURLY_BRACKET: 125 /* } */
,
    CHAR_HYPHEN_MINUS: 45 /* - */
,
    CHAR_PLUS: 43 /* + */
,
    CHAR_DOUBLE_QUOTE: 34 /* " */
,
    CHAR_SINGLE_QUOTE: 39 /* ' */
,
    CHAR_PERCENT: 37 /* % */
,
    CHAR_SEMICOLON: 59 /* ; */
,
    CHAR_CIRCUMFLEX_ACCENT: 94 /* ^ */
,
    CHAR_GRAVE_ACCENT: 96 /* ` */
,
    CHAR_AT: 64 /* @ */
,
    CHAR_AMPERSAND: 38 /* & */
,
    CHAR_EQUAL: 61 /* = */
,

    // Digits
    CHAR_0: 48 /* 0 */
,
    CHAR_9: 57 /* 9 */
,

    EOL: "\n",
};

/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var primordials = {
    uncurryThis: (function () {
        const { apply, bind, call } = Function.prototype;
        return bind.bind(call);
    })(),

    JSONParse(self) {
        return JSON.parse(self);
    },


    /**
     * Math start
     */
    MathAbs(self) {
        return Math.abs(self);
    }, //typeof Math.abs
    MathAcos(self) {
        return Math.acos(self);
    }, // typeof Math.acos
    MathAcosh(self) {
        return Math.acosh(self);
    }, //typeof Math.acosh
    MathAsin(self) {
        return Math.asin(self);
    }, //typeof Math.asin
    MathAsinh(self) {
        return Math.asinh(self);
    }, //typeof Math.asinh
    MathAtan(self) {
        return Math.atan(self);
    }, //typeof Math.atan
    MathAtanh(self) {
        return Math.atanh(self);
    }, //typeof Math.atanh
    MathAtan2(self) {
        return Math.atan2(self);
    }, //typeof Math.atan2
    MathCeil(self) {
        return Math.ceil(self);
    }, //typeof Math.ceil
    MathCbrt(self) {
        return Math.cbrt(self);
    }, //typeof Math.cbrt
    MathExpm1(self) {
        return Math.expm1(self);
    }, //typeof Math.expm1
    MathClz32(self) {
        return Math.clz32(self);
    }, //typeof Math.clz32
    MathCos(self) {
        return Math.cos(self);
    }, //typeof Math.cos
    MathCosh(self) {
        return Math.cosh(self);
    }, //typeof Math.cosh
    MathExp(self) {
        return Math.exp(self);
    }, //typeof Math.exp

    MathFround(self) {
        return Math.fround(self);
    }, //typeof Math.fround
    MathHypot(self) {
        return Math.hypot(self);
    }, //typeof Math.hypot
    MathImul(self) {
        return Math.imul(self);
    }, //typeof Math.imul
    MathLog(self) {
        return Math.log(self);
    }, //typeof Math.log
    MathLog1p(self) {
        return Math.log(self);
    }, //typeof Math.log1p
    MathLog2(self) {
        return Math.log2(self);
    }, //typeof Math.log2
    MathLog10(self) {
        return Math.log10(self);
    }, //typeof Math.log10
    MathMax(...selfs) {
        return Math.max(...selfs);
    }, //typeof Math.max
    MathMaxApply(self) {
        return Math.max.apply(null, self);
    }, //StaticApply<typeof Math.max>
    MathMin(self) {
        return Math.min(self);
    }, //typeof Math.min
    MathPow(self) {
        return Math.pow(self);
    }, //typeof Math.pow
    MathRandom() {
        return Math.random();
    }, //typeof Math.random
    MathRound(self) {
        return Math.round(self);
    }, //typeof Math.round
    MathSign(self) {
        return Math.sign(self);
    }, //typeof Math.sign
    MathSin(self) {
        return Math.sin(self);
    }, //typeof Math.sin
    MathSinh(self) {
        return Math.sinh(self);
    }, //typeof Math.sinh
    MathSqrt(self) {
        return Math.sqrt(self);
    }, //typeof Math.sqrt
    MathTan(self) {
        return Math.tan(self);
    }, //typeof Math.tan
    MathTanh(self) {
        return Math.tanh(self);
    }, //typeof Math.tanh
    MathTrunc(self) {
        return Math.trunc(self);
    }, //typeof Math.trunc
    MathE() {
        return Math.E;
    }, //typeof Math.E
    MathLN10() {
        return Math.LN10;
    }, //typeof Math.LN10
    MathLN2() {
        return Math.LN2;
    }, //typeof Math.LN2
    MathLOG10E() {
        return Math.LOG10E;
    }, //typeof Math.LOG10E
    MathLOG2E() {
        return Math.LOG2E;
    }, //typeof Math.LOG2E
    MathPI() {
        return Math.PI;
    }, //typeof Math.PI
    MathSQRT1_2() {
        return Math.SQRT1_2;
    }, //typeof Math.SQRT1_2
    MathSQRT2() {
        return Math.SQRT2;
    }, //typeof Math.SQRT2

    /**
     * Math end
     */

    /**
     * Reflect start
     */
    ReflectDefineProperty: Reflect.defineProperty, //typeof Reflect.defineProperty
    ReflectDeleteProperty: Reflect.deleteProperty, // typeof Reflect.deleteProperty
    ReflectApply: Reflect.apply,
    ReflectConstruct: Reflect.construct, // typeof Reflect.construct
    ReflectGet: Reflect.get, // typeof Reflect.get
    ReflectGetOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor, // typeof Reflect.getOwnPropertyDescriptor
    ReflectGetPrototypeOf: Reflect.getPrototypeOf, // typeof Reflect.getPrototypeOf
    ReflectHas: Reflect.has, // typeof Reflect.has
    ReflectIsExtensible: Reflect.isExtensible, // typeof Reflect.isExtensible
    ReflectOwnKeys: Reflect.ownKeys, // typeof Reflect.ownKeys
    ReflectPreventExtensions: Reflect.preventExtensions, // typeof Reflect.preventExtensions
    ReflectSet: Reflect.set, //typeof Reflect.set
    ReflectSetPrototypeOf: Reflect.setPrototypeOf, // typeof Reflect.setPrototypeOf
    // /**
    //  * Reflect end
    //  */
    //
    // AggregateError: require("./AggregateError"),

    /**
     * Array start
     */
    ArrayFrom(self, fn) {
        return Array.from(self, fn);
    },

    ArrayIsArray(self) {
        return Array.isArray(self);
    },

    ArrayPrototypeIncludes(self, el) {
        return self.includes(el);
    },

    ArrayPrototypeFilter(self, fn) {
        return self.filter(fn);
    },

    ArrayPrototypeIndexOf(self, el) {
        return self.indexOf(el);
    },

    ArrayPrototypeJoin(self, sep) {
        return self.join(sep);
    },

    ArrayPrototypeMap(self, fn) {
        return self.map(fn);
    },

    ArrayPrototypePop(self, el) {
        return self.pop(el);
    },

    ArrayPrototypePush(self, el) {
        return self.push(el);
    },

    ArrayPrototypeSlice(self, start, end) {
        return self.slice(start, end);
    },

    ArrayPrototypeSplice(self, start, end, ...args) {
        return self.splice(start, end, ...args);
    },

    ArrayPrototypeUnshift(self, value) {
        return self.unshift(value);
    },

    /**
     * Array end
     */

    /**
     * Map start
     */

    MapPrototypeGet: Map.prototype.get,
    /**
     * Map end
     */
    /**
     * Error start
     */
    Error,
    ErrorCaptureStackTrace: Error.captureStackTrace,
    ErrorPrototypeToString: Error.prototype.toString,
    RangeError,
    /**
     * Error end
     */

    /**
     * JSON start
     */
    JSONStringify: JSON.stringify,

    /**
     * JSON end
     */
    FunctionPrototypeCall(fn, thisArgs, ...args) {
        return fn.call(thisArgs, ...args);
    },

    FunctionPrototypeBind(fn, thisArgs, ...args) {
        return fn.bind(thisArgs, ...args);
    },

    FunctionPrototypeSymbolHasInstance(self, instance) {
        return Function.prototype[Symbol.hasInstance].call(self, instance);
    },

    MathFloor: Math.floor,
    Number,
    NumberIsInteger: Number.isInteger,
    NumberIsNaN: Number.isNaN,
    NumberMAX_SAFE_INTEGER: Number.MAX_SAFE_INTEGER,
    NumberMIN_SAFE_INTEGER: Number.MIN_SAFE_INTEGER,
    NumberParseInt: Number.parseInt,
    NumberIsFinite: Number.isFinite,

    NumberPrototypeToString(value, radix) {
        return value.toString(radix);
    },

    /**
     * Object start
     */

    ObjectPrototypeHasOwnProperty(self, name) {
        return Object.prototype.hasOwnProperty.call(self, name);
    },

    ObjectAssign: Object.assign,

    ObjectDefineProperties(self, props) {
        return Object.defineProperties(self, props);
    },

    ObjectDefineProperty(self, name, prop) {
        return Object.defineProperty(self, name, prop);
    },

    ObjectGetOwnPropertyDescriptor(self, name) {
        return Object.getOwnPropertyDescriptor(self, name);
    },

    ObjectKeys(obj) {
        return Object.keys(obj);
    },

    ObjectCreate(obj) {
        return Object.create(obj);
    },

    ObjectFreeze(obj) {
        return Object.freeze(obj);
    },

    ObjectEntries(obj) {
        return Object.entries(obj);
    },

    ObjectSetPrototypeOf(target, proto) {
        return Object.setPrototypeOf(target, proto);
    },

    ObjectPrototypeToString(obj) {
        return obj.toString();
    },

    ObjectPrototypePropertyIsEnumerable(self, val) {
        return self.propertyIsEnumerable(val);
    },

    ObjectIsExtensible: Object.isExtensible,

    /**
     * Object end
     */
    Promise,

    PromisePrototypeCatch(self, fn) {
        return self.catch(fn);
    },

    PromisePrototypeThen(self, thenFn, catchFn) {
        return self.then(thenFn, catchFn);
    },

    PromiseReject(err) {
        return Promise.reject(err);
    },

    RegExpPrototypeTest(self, value) {
        return self.test(value);
    },

    SafeSet: Set,
    String,

    StringPrototypeSlice(self, start, end) {
        return self.slice(start, end);
    },

    StringPrototypeToLowerCase(self) {
        return self.toLowerCase();
    },

    StringPrototypeToUpperCase(self) {
        return self.toUpperCase();
    },

    StringPrototypeTrim(self) {
        return self.trim();
    },

    StringPrototypeCharCodeAt(value, index) {
        return value.charCodeAt(index);
    },

    StringPrototypeLastIndexOf(value, separator) {
        return value.lastIndexOf(separator);
    },

    StringPrototypeCharAt(value, index) {
        return value.charAt(index);
    },

    StringPrototypeIndexOf(value, index) {
        return value.indexOf(index);
    },

    StringPrototypeStartsWith(value, index) {
        return value.startsWith(index);
    },

    StringPrototypeIncludes(self, value, start) {
        return self.includes(value, start);
    },

    StringPrototypePadStart(self, targetLength, padString) {
        return self.padStart(targetLength, padString);
    },

    StringPrototypeReplace(self, searchValue, replaceValue) {
        return self.replace(searchValue, replaceValue);
    },

    DatePrototypeGetDate(date) {
        return date.getDate();
    },

    DatePrototypeGetHours(date) {
        return date.getHours();
    },

    DatePrototypeGetMinutes(date) {
        return date.getMinutes();
    },

    DatePrototypeGetMonth(date) {
        return date.getMonth();
    },

    DatePrototypeGetSeconds(date) {
        return date.getSeconds();
    },

    Symbol,
    SymbolAsyncIterator: Symbol.asyncIterator,
    SymbolHasInstance: Symbol.hasInstance,
    SymbolIterator: Symbol.iterator,

    TypedArrayPrototypeSet(self, buf, len) {
        return self.set(buf, len);
    },

    decodeURIComponent,

    Uint8Array,
    Int8Array,
    Array,
    Date,

};

const nodeInternalPrefix = "__node_internal_";
const { ObjectDefineProperty, ArrayIsArray, ArrayPrototypeIncludes, NumberIsNaN } = primordials;
const hideStackFrames = (fn) => {
    // We rename the functions that will be hidden to cut off the stacktrace
    // at the outermost one
    const hidden = nodeInternalPrefix + fn.name;
    ObjectDefineProperty(fn, "name", { __proto__: null, value: hidden });
    return fn;
};
var validateString$1 = hideStackFrames((value, name) => {
    if (typeof value !== "string") {
        throw new Error("ERR_INVALID_ARG_TYPE value:" + value + " name:" + name);
    }
});
var validateFunction = hideStackFrames((value, name) => {
    if (typeof value !== "function")
        throw new Error("ERR_INVALID_ARG_TYPE value:" + value + " name:" + name);
});
var validateAbortSignal = hideStackFrames((signal, name) => {
    if (
        signal !== undefined &&
        (signal === null || typeof signal !== "object" || !("aborted" in signal))
    ) {
        throw new Error("ERR_INVALID_ARG_TYPE value:" + value + " name:" + name);
    }
});

var validateObject$1 = hideStackFrames((value, name, options) => {
    const useDefaultOptions = options == null;
    const allowArray = useDefaultOptions ? false : options.allowArray;
    const allowFunction = useDefaultOptions ? false : options.allowFunction;
    const nullable = useDefaultOptions ? false : options.nullable;
    if (
        (!nullable && value === null) ||
        (!allowArray && ArrayIsArray(value)) ||
        (typeof value !== "object" &&
        (!allowFunction || typeof value !== "function"))
    ) {
        throw new Error("ERR_INVALID_ARG_TYPE value:" + value + " name:" + name);
    }
});

var validateNumber = function validateNumber(value, name, min = undefined, max) {
    if (typeof value !== 'number')
        throw new Error("ERR_INVALID_ARG_TYPE value:" + value + " name:" + name);

    if ((min != null && value < min) || (max != null && value > max) ||
    ((min != null || max != null) && NumberIsNaN(value))) {
        throw new Error('ERR_OUT_OF_RANGE, name:' +
        name + ', ' +
        `${min != null ? `>= ${min}` : ''}${min != null && max != null ? ' && ' : ''}${max != null ? `<= ${max}` : ''}` +
        value);
    }
};

var validateBoolean = function validateBoolean(value, name) {
    if (typeof value !== 'boolean')
        throw new Error("ERR_INVALID_ARG_TYPE value:" + value + " name:" + name);
};

var validateArray = hideStackFrames((value, name, minLength = 0) => {
    if (!Array.isArray(value)) {
        throw new Error('Array:' + name);
    }
    if (value.length < minLength) {
        const reason = `must be longer than ${minLength}`;
        throw new Error('ERR_INVALID_ARG_VALUE name:' + name + ',value:' + value + ',reason:' + reason);
    }
});

var validateUnion = function validateUnion(value, name, union) {
    if (!ArrayPrototypeIncludes(union, value)) {
        throw new Error('ERR_INVALID_ARG_TYPE, name:' + name + ',union:' + union + ',value:' + value);
    }
};

var validator = {
    validateString: validateString$1,
    validateFunction: validateFunction,
    validateAbortSignal: validateAbortSignal,
    validateObject: validateObject$1,
    validateNumber: validateNumber,
    validateBoolean: validateBoolean,
    validateArray: validateArray,
    validateUnion: validateUnion
};

// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

const {
    StringPrototypeCharCodeAt,
    StringPrototypeSlice,
    StringPrototypeLastIndexOf,
    FunctionPrototypeBind,
} = primordials;
const { validateString, validateObject } = validator;

var sep = "/";

function isPathSeparator(code) {
    return code === constants.CHAR_FORWARD_SLASH;
}

function _format(sep, pathObject) {
    validateObject(pathObject, "pathObject");
    const dir = pathObject.dir || pathObject.root;
    const base =
        pathObject.base || `${pathObject.name || ""}${pathObject.ext || ""}`;
    if (!dir) {
        return base;
    }
    return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;
}

function basename(path, ext) {
    if (ext !== undefined) validateString(ext, "ext");
    validateString(path, "path");
    let start = 0;
    let end = -1;
    let matchedSlash = true;

    if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
        if (ext === path) return "";
        let extIdx = ext.length - 1;
        let firstNonSlashEnd = -1;
        for (let i = path.length - 1; i >= start; --i) {
            const code = StringPrototypeCharCodeAt(path, i);
            if (isPathSeparator(code)) {
                // If we reached a path separator that was not part of a set of path
                // separators at the end of the string, stop now
                if (!matchedSlash) {
                    start = i + 1;
                    break;
                }
            } else {
                if (firstNonSlashEnd === -1) {
                    // We saw the first non-path separator, remember this index in case
                    // we need it if the extension ends up not matching
                    matchedSlash = false;
                    firstNonSlashEnd = i + 1;
                }
                if (extIdx >= 0) {
                    // Try to match the explicit extension
                    if (code === StringPrototypeCharCodeAt(ext, extIdx)) {
                        if (--extIdx === -1) {
                            // We matched the extension, so mark this as the end of our path
                            // component
                            end = i;
                        }
                    } else {
                        // Extension does not match, so our result is the entire path
                        // component
                        extIdx = -1;
                        end = firstNonSlashEnd;
                    }
                }
            }
        }

        if (start === end) end = firstNonSlashEnd;
        else if (end === -1) end = path.length;
        return StringPrototypeSlice(path, start, end);
    }
    for (let i = path.length - 1; i >= start; --i) {
        if (isPathSeparator(StringPrototypeCharCodeAt(path, i))) {
            // If we reached a path separator that was not part of a set of path
            // separators at the end of the string, stop now
            if (!matchedSlash) {
                start = i + 1;
                break;
            }
        } else if (end === -1) {
            // We saw the first non-path separator, mark this as the end of our
            // path component
            matchedSlash = false;
            end = i + 1;
        }
    }

    if (end === -1) return "";
    return StringPrototypeSlice(path, start, end);
}

function dirname(path) {
    validateString(path, "path");
    const len = path.length;
    if (len === 0) return ".";
    let rootEnd = -1;
    let offset = 0;
    const code = StringPrototypeCharCodeAt(path, 0);

    if (len === 1) {
        // `path` contains just a path separator, exit early to avoid
        // unnecessary work or a dot.
        return isPathSeparator(code) ? path : ".";
    }

    // Try to match a root
    if (isPathSeparator(code)) {
        // Possible UNC root

        rootEnd = offset = 1;

        if (isPathSeparator(StringPrototypeCharCodeAt(path, 1))) {
            // Matched double path separator at beginning
            let j = 2;
            let last = j;
            // Match 1 or more non-path separators
            while (j < len && !isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
                j++;
            }
            if (j < len && j !== last) {
                // Matched!
                last = j;
                // Match 1 or more path separators
                while (j < len && isPathSeparator(StringPrototypeCharCodeAt(path, j))) {
                    j++;
                }
                if (j < len && j !== last) {
                    // Matched!
                    last = j;
                    // Match 1 or more non-path separators
                    while (
                        j < len &&
                        !isPathSeparator(StringPrototypeCharCodeAt(path, j))
                    ) {
                        j++;
                    }
                    if (j === len) {
                        // We matched a UNC root only
                        return path;
                    }
                    if (j !== last) {
                        // We matched a UNC root with leftovers

                        // Offset by 1 to include the separator after the UNC root to
                        // treat it as a "normal root" on top of a (UNC) root
                        rootEnd = offset = j + 1;
                    }
                }
            }
        }
        // Possible device root
    }

    let end = -1;
    let matchedSlash = true;
    for (let i = len - 1; i >= offset; --i) {
        if (isPathSeparator(StringPrototypeCharCodeAt(path, i))) {
            if (!matchedSlash) {
                end = i;
                break;
            }
        } else {
            // We saw the first non-path separator
            matchedSlash = false;
        }
    }

    if (end === -1) {
        if (rootEnd === -1) return ".";

        end = rootEnd;
    }
    return StringPrototypeSlice(path, 0, end);
}

function join(...args) {
    if (args.length === 0) return ".";
    let joined;
    for (let i = 0; i < args.length; ++i) {
        const arg = args[i];
        validateString(arg, "path");
        if (arg.length > 0) {
            if (joined === undefined) joined = arg;
            else joined += `/${arg}`;
        }
    }
    if (joined === undefined) return ".";
    return normalize(joined);
}

function normalize(path) {
    validateString(path, "path");

    if (path.length === 0) return ".";

    const isAbsolute =
        StringPrototypeCharCodeAt(path, 0) === constants.CHAR_FORWARD_SLASH;
    const trailingSeparator =
        StringPrototypeCharCodeAt(path, path.length - 1) ===
        constants.CHAR_FORWARD_SLASH;

    // Normalize the path
    path = normalizeString(path,!isAbsolute, "/");

    if (path.length === 0) {
        if (isAbsolute) return "/";
        return trailingSeparator ? "./" : ".";
    }
    if (trailingSeparator) path += "/";

    return isAbsolute ? `/${path}` : path;
}

function normalizeString(path, allowAboveRoot, separator) {
    let res = "";
    let lastSegmentLength = 0;
    let lastSlash = -1;
    let dots = 0;
    let code = 0;
    for (let i = 0; i <= path.length; ++i) {
        if (i < path.length) code = StringPrototypeCharCodeAt(path, i);
        else if (isPathSeparator(code)) break;
        else code = constants.CHAR_FORWARD_SLASH;

        if (isPathSeparator(code)) {
            if (lastSlash === i - 1 || dots === 1) ; else if (dots === 2) {
                if (
                    res.length < 2 ||
                    lastSegmentLength !== 2 ||
                    StringPrototypeCharCodeAt(res, res.length - 1) !==
                    constants.CHAR_DOT ||
                    StringPrototypeCharCodeAt(res, res.length - 2) !== constants.CHAR_DOT
                ) {
                    if (res.length > 2) {
                        const lastSlashIndex = StringPrototypeLastIndexOf(res, separator);
                        if (lastSlashIndex === -1) {
                            res = "";
                            lastSegmentLength = 0;
                        } else {
                            res = StringPrototypeSlice(res, 0, lastSlashIndex);
                            lastSegmentLength =
                            res.length - 1 - StringPrototypeLastIndexOf(res, separator);
                        }
                        lastSlash = i;
                        dots = 0;
                        continue;
                    } else if (res.length !== 0) {
                        res = "";
                        lastSegmentLength = 0;
                        lastSlash = i;
                        dots = 0;
                        continue;
                    }
                }
                if (allowAboveRoot) {
                    res += res.length > 0 ? `${separator}..` : "..";
                    lastSegmentLength = 2;
                }
            } else {
                if (res.length > 0)
                    res += `${separator}${StringPrototypeSlice(path, lastSlash + 1, i)}`;
                else res = StringPrototypeSlice(path, lastSlash + 1, i);
                lastSegmentLength = i - lastSlash - 1;
            }
            lastSlash = i;
            dots = 0;
        } else if (code === constants.CHAR_DOT && dots !== -1) {
            ++dots;
        } else {
            dots = -1;
        }
    }
    return res;
}

function resolve(...args) {
    let resolvedPath = "";
    let resolvedAbsolute = false;

    for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
        const path = i >= 0 ? args[i] : sep;

        validateString(path, "path");

        // Skip empty entries
        if (path.length === 0) {
            continue;
        }

        resolvedPath = `${path}/${resolvedPath}`;
        resolvedAbsolute =
        StringPrototypeCharCodeAt(path, 0) === constants.CHAR_FORWARD_SLASH;
    }

    // At this point the path should be resolved to a full absolute path, but
    // handle relative paths to be safe (might happen when process.cwd() fails)

    // Normalize the path
    resolvedPath = normalizeString(resolvedPath,!resolvedAbsolute, "/");

    if (resolvedAbsolute) {
        return `/${resolvedPath}`;
    }
    return resolvedPath.length > 0 ? resolvedPath : ".";
}

function isAbsolute(path) {
    validateString(path, "path");
    return (
        path.length > 0 &&
        StringPrototypeCharCodeAt(path, 0) === constants.CHAR_FORWARD_SLASH
    );
}

function relative(from, to) {
    validateString(from, "from");
    validateString(to, "to");

    if (from === to) return "";

    // Trim leading forward slashes.
    from = resolve(from);
    to = resolve(to);

    if (from === to) return "";

    const fromStart = 1;
    const fromEnd = from.length;
    const fromLen = fromEnd - fromStart;
    const toStart = 1;
    const toLen = to.length - toStart;

    // Compare paths to find the longest common path from root
    const length = fromLen < toLen ? fromLen : toLen;
    let lastCommonSep = -1;
    let i = 0;
    for (; i < length; i++) {
        const fromCode = StringPrototypeCharCodeAt(from, fromStart + i);
        if (fromCode !== StringPrototypeCharCodeAt(to, toStart + i)) break;
        else if (fromCode === constants.CHAR_FORWARD_SLASH) lastCommonSep = i;
    }
    if (i === length) {
        if (toLen > length) {
            if (
                StringPrototypeCharCodeAt(to, toStart + i) ===
                constants.CHAR_FORWARD_SLASH
            ) {
                // We get here if `from` is the exact base path for `to`.
                // For example: from='/foo/bar'; to='/foo/bar/baz'
                return StringPrototypeSlice(to, toStart + i + 1);
            }
            if (i === 0) {
                // We get here if `from` is the root
                // For example: from='/'; to='/foo'
                return StringPrototypeSlice(to, toStart + i);
            }
        } else if (fromLen > length) {
            if (
                StringPrototypeCharCodeAt(from, fromStart + i) ===
                constants.CHAR_FORWARD_SLASH
            ) {
                // We get here if `to` is the exact base path for `from`.
                // For example: from='/foo/bar/baz'; to='/foo/bar'
                lastCommonSep = i;
            } else if (i === 0) {
                // We get here if `to` is the root.
                // For example: from='/foo/bar'; to='/'
                lastCommonSep = 0;
            }
        }
    }

    let out = "";
    // Generate the relative path based on the path difference between `to`
    // and `from`.
    for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
        if (
            i === fromEnd ||
            StringPrototypeCharCodeAt(from, i) === constants.CHAR_FORWARD_SLASH
        ) {
            out += out.length === 0 ? ".." : "/..";
        }
    }

    // Lastly, append the rest of the destination (`to`) path that comes after
    // the common path parts.
    return `${out}${StringPrototypeSlice(to, toStart + lastCommonSep)}`;
}

function extname(path) {
    validateString(path, "path");
    let startDot = -1;
    let startPart = 0;
    let end = -1;
    let matchedSlash = true;
    // Track the state of characters (if any) we see before our first dot and
    // after any path separator we find
    let preDotState = 0;
    for (let i = path.length - 1; i >= 0; --i) {
        path.charcode;
        const code = StringPrototypeCharCodeAt(path, i);
        if (code === constants.CHAR_FORWARD_SLASH) {
            // If we reached a path separator that was not part of a set of path
            // separators at the end of the string, stop now
            if (!matchedSlash) {
                startPart = i + 1;
                break;
            }
            continue;
        }
        if (end === -1) {
            // We saw the first non-path separator, mark this as the end of our
            // extension
            matchedSlash = false;
            end = i + 1;
        }
        if (code === constants.CHAR_DOT) {
            // If this is our first dot, mark it as the start of our extension
            if (startDot === -1) startDot = i;
            else if (preDotState !== 1) preDotState = 1;
        } else if (startDot !== -1) {
            // We saw a non-dot and non-path separator before our dot, so we should
            // have a good chance at having a non-empty extension
            preDotState = -1;
        }
    }

    if (
        startDot === -1 ||
        end === -1 ||
        // We saw a non-dot character immediately before the dot
        preDotState === 0 ||
        // The (right-most) trimmed path component is exactly '..'
        (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)
    ) {
        return "";
    }
    return StringPrototypeSlice(path, startDot, end);
}

const format = FunctionPrototypeBind(_format, null, "/");

function parse(path) {
    validateString(path, "path");

    const ret = {
        root: "",
        dir: "",
        base: "",
        ext: "",
        name: ""
    };
    if (path.length === 0) return ret;
    const isAbsolute =
        StringPrototypeCharCodeAt(path, 0) === constants.CHAR_FORWARD_SLASH;
    let start;
    if (isAbsolute) {
        ret.root = "/";
        start = 1;
    } else {
        start = 0;
    }
    let startDot = -1;
    let startPart = 0;
    let end = -1;
    let matchedSlash = true;
    let i = path.length - 1;

    // Track the state of characters (if any) we see before our first dot and
    // after any path separator we find
    let preDotState = 0;

    // Get non-dir info
    for (; i >= start; --i) {
        const code = StringPrototypeCharCodeAt(path, i);
        if (code === constants.CHAR_FORWARD_SLASH) {
            // If we reached a path separator that was not part of a set of path
            // separators at the end of the string, stop now
            if (!matchedSlash) {
                startPart = i + 1;
                break;
            }
            continue;
        }
        if (end === -1) {
            // We saw the first non-path separator, mark this as the end of our
            // extension
            matchedSlash = false;
            end = i + 1;
        }
        if (code === constants.CHAR_DOT) {
            // If this is our first dot, mark it as the start of our extension
            if (startDot === -1) startDot = i;
            else if (preDotState !== 1) preDotState = 1;
        } else if (startDot !== -1) {
            // We saw a non-dot and non-path separator before our dot, so we should
            // have a good chance at having a non-empty extension
            preDotState = -1;
        }
    }

    if (end !== -1) {
        const start = startPart === 0 && isAbsolute ? 1 : startPart;
        if (
            startDot === -1 ||
            // We saw a non-dot character immediately before the dot
            preDotState === 0 ||
            // The (right-most) trimmed path component is exactly '..'
            (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)
        ) {
            ret.base = ret.name = StringPrototypeSlice(path, start, end);
        } else {
            ret.name = StringPrototypeSlice(path, start, startDot);
            ret.base = StringPrototypeSlice(path, start, end);
            ret.ext = StringPrototypeSlice(path, startDot, end);
        }
    }

    if (startPart > 0) ret.dir = StringPrototypeSlice(path, 0, startPart - 1);
    else if (isAbsolute) ret.dir = "/";

    return ret;
}

var path = {
    basename,
    dirname,
    extname,
    format,
    parse,
    sep,
    join,
    resolve,
    isAbsolute,
    relative,
    normalize,
};
var path_1 = path.basename;
var path_2 = path.dirname;
var path_3 = path.extname;
var path_4 = path.format;
var path_5 = path.parse;
var path_6 = path.sep;
var path_7 = path.join;
var path_8 = path.resolve;
var path_9 = path.isAbsolute;
var path_10 = path.relative;
var path_11 = path.normalize;

export {
    path_1 as basename,
    path as default,
    path_2 as dirname,
    path_3 as extname,
    path_4 as format,
    path_9 as isAbsolute,
    path_7 as join,
    path_11 as normalize,
    path_5 as parse,
    path_10 as relative,
    path_8 as resolve,
    path_6 as sep
};
